Java JavaScript Python C# C C++ Go Kotlin PHP Swift R Ruby TypeScript Scala SQL Perl rust VisualBasic Matlab Julia

Inheritance → Inheritance & Constructors

Inheritance

Inheritance & Constructors

Constructors in Python inheritance

When you create a class that inherits from another class (the parent or superclass), you might want to customize how objects of the child class are initialized. This is where the constructor, the `__init__` method, comes into play. Basics The constructor (`__init__`) of a class is a special method that gets automatically called when you create a new instance (object) of that class. Its primary purpose is to initialize the object's attributes (data). In inheritance, if a child class doesn't define its own `__init__` method, it automatically inherits the `__init__` method of its parent class. This means that when you create an instance of the child class, the parent's initialization logic will be executed.

Why Override the Constructor?

Often, the child class needs to initialize its own unique attributes in addition to or instead of the attributes initialized by the parent. To achieve this, the child class can define its own `__init__` method, effectively *overriding* the parent's `__init__`. How to Properly Override and Extend When a child class overrides the `__init__` method, it's crucial to consider whether you still need the parent's initialization logic to run. Here are the common approaches: Calling the Parent's Constructor using `super()`: This is the recommended way to invoke the parent's `__init__` from the child's `__init__`. `super()` provides a way to access methods of the parent class without explicitly naming the parent class. This makes your code more maintainable and robust, especially in complex inheritance hierarchies. Calling the Parent's Constructor Directly (Less Recommended): You can also call the parent's `__init__` directly using the parent class name (e.g., `Parent.__init__(self, ...)`). However, this approach is generally discouraged because it can lead to issues with method resolution order in multiple inheritance scenarios.

Examples

Example 1: Child Class Inherits the Parent's Constructor
Child Class Inherits the Parent's Constructor class Animal: def __init__(self, name): print("Animal constructor called") self.name = name def speak(self): print("Generic animal sound") class Dog(Animal): def bark(self): print("Woof!") my_dog = Dog("Buddy") print(my_dog.name) my_dog.speak() my_dog.bark()

Output

Animal constructor called Buddy Generic animal sound Woof!
In this example, the `Dog` class doesn't have its own `__init__` method. Therefore, when we create an instance of `Dog`, the `__init__` method of the `Animal` class is automatically called, initializing the `name` attribute.
Example 2: Child Class Overrides the Constructor without Calling the Parent
Child Class Overrides the Constructor class Car: def __init__(self, color): print("Car constructor called") self.color = color def start(self): print("Car started") class ElectricCar(Car): def __init__(self, model): print("ElectricCar constructor called") self.model = model def charge(self): print("Charging...") my_electric_car = ElectricCar("Tesla Model 3") print(my_electric_car.model) # print(my_electric_car.color) # This would raise an AttributeError my_electric_car.charge() my_electric_car.start() # This method is inherited

Output

ElectricCar constructor called Tesla Model 3 Charging... Car started
Here, `ElectricCar` defines its own `__init__` which only initializes the `model` attribute. The `color` attribute from the `Car` class is not initialized for `ElectricCar` objects because the parent's `__init__` was not called. This can lead to unexpected behavior or errors if the child class relies on attributes initialized by the parent.
Example 3: Child Class Overrides and Extends the Constructor using `super()`
Child Class Overrides and Extends the Constructor using `super()` class Shape: def __init__(self, color): print("Shape constructor called") self.color = color def describe_color(self): print(f"This shape is {self.color}") class Circle(Shape): def __init__(self, color, radius): print("Circle constructor called") super().__init__(color) # Call the parent's __init__ to initialize color self.radius = radius def area(self): return 3.14 * self.radius * self.radius my_circle = Circle("blue", 5) print(my_circle.color) print(my_circle.radius) my_circle.describe_color() print(f"Area: {my_circle.area()}")

Output

Circle constructor called Shape constructor called blue 5 This shape is blue Area: 78.5
In this example, the `Circle` class's `__init__` first calls the `__init__` of the `Shape` class using `super().__init__(color)` to initialize the `color` attribute. Then, it initializes its own `radius` attribute. This ensures that both the parent's and the child's initialization logic is executed.
Example 4: Child Class Overrides and Extends the Constructor using Direct Parent Call (Less Recommended)
Child Class Overrides and Extends the Constructor class Device: def __init__(self, brand): print("Device constructor called") self.brand = brand def power_on(self): print("Device powered on") class Smartphone(Device): def __init__(self, brand, model): print("Smartphone constructor called") Device.__init__(self, brand) # Calling parent's __init__ directly self.model = model def take_photo(self): print("Taking a photo") my_smartphone = Smartphone("Samsung", "S23") print(my_smartphone.brand) print(my_smartphone.model) my_smartphone.power_on() my_smartphone.take_photo()

Output

Smartphone constructor called Device constructor called Samsung S23 Device powered on Taking a photo
This example achieves a similar result to the previous one but uses the direct call to `Device.__init__`. While it works in this simple case, using `super()` is generally preferred for better handling of more complex inheritance structures.
Key points ✦ The constructor (`__init__`) in a child class can either be inherited from the parent or overridden. ✦ If a child class needs to initialize its own attributes *in addition* to the parent's, it should override the `__init__` and explicitly call the parent's `__init__` using `super()`. ✦ Using `super()` promotes cleaner and more maintainable code, especially in scenarios with multiple inheritance. ✦ Failing to call the parent's `__init__` when overriding can lead to the child object not being properly initialized with the parent's attributes. By understanding how constructors work in inheritance, you can effectively manage the initialization of objects in your class hierarchies, ensuring that both parent and child classes contribute to the proper setup of their instances.

Tutorials